

package org.ring.rpc;

import org.ring.common.URL;
import org.ring.common.transport.Connection;
import org.ring.common.transport.DefaultMessageHandlerRegistry;
import org.ring.common.transport.HandlerRegistry;
import org.ring.common.transport.MessageHandler;
import org.ring.common.transport.TcpServerTransport;
import org.ring.common.utils.reflect.MethodDescriptor;
import org.ring.common.utils.reflect.ServiceDescriptor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @since 2024-10-26 15:19
 */
public class RingServer {

    private int port;
    private TcpServerTransport transport;
    private HandlerRegistry handlerRegistry ;
    private Map<String,Object> providers = new HashMap<>();

    public RingServer(){
    }

    public void addService(ProviderConfig providerConfig){
        providers.put(providerConfig.getInterfaceName(),providerConfig.getRef());
        try {
            ServiceRepository.getInstance().registerService(Class.forName(providerConfig.getInterfaceName()));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }


    void start(){

        DefaultMessageHandlerRegistry messageHandlerRegistry = new DefaultMessageHandlerRegistry();
        this.handlerRegistry = messageHandlerRegistry;
        messageHandlerRegistry.register(Invocation.class, new MessageHandler() {
            @Override
            public CompletableFuture handle(Connection connection, Object input) {
                Invocation invocation = (Invocation) input;
                String interfaceName = invocation.getInterfaceName();
                Object serviceObj = providers.get(interfaceName);
                ServiceDescriptor serviceDescriptor = ServiceRepository.getInstance().lookup(interfaceName);
                MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(invocation.getMethodName(),invocation.getParamDescriptor());
                Method method = methodDescriptor.getMethod();
                Object returnObj = null;
                try {
                    returnObj = method.invoke(serviceObj,invocation.getArgs());
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
                return CompletableFuture.completedFuture(returnObj);
            }
        });

        URL url = new URL("ring","localhost",10000);

        transport = new TcpServerTransport(url);
        transport.handlerRegistry(handlerRegistry);
        transport.start();

    }

    public void setPort(int port) {
        this.port = port;
    }
}
